// Copyright (C) joyinter
// All rights reserved.
// 
// Author : Jiang Li
// Date   : 2004-11-17

#ifndef __DB_UTILITY_H_COMMON_SVR_BASE__
#define __DB_UTILITY_H_COMMON_SVR_BASE__

#pragma once

#include "db_source.h"
#include "db_session.h"
#include "db_command.h"

namespace JoyServer
{

class CJoyServer;

namespace JoyDbUtility
{

#define JOY_DB_TRY_OPEN_SESSION(sess, source) \
    CJoyDbSession sess;\
    hr = sess.Open(source);\
    if(FAILED(hr))\
    {\
        pServer->m_showInfo->QueueTimeColorText(InfoColor_Error,\
            "failed to open db session.\n"\
            "    error code : %d.\n"\
            "    ini string : %s.\n", hr, (PCSTR)source.m_initString);\
        return false;\
    }\

//bool OpenDbSession(CJoyServer* pServer, CJoyDbSession& sess, CJoyDbSource& source);

class CJoyOpenDbSession
{
protected:
    PCSTR   m_file;
    int     m_line;
public:
    CJoyOpenDbSession(PCSTR pszFile, int nLine)
        : m_file(pszFile), m_line(nLine)
    {
    }

    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbSource& source);
};

#define JoyOpenDbSession CJoyOpenDbSession(__FILE__, __LINE__)

// database config utilities.
bool LoadDbSource(CJoyServer* pServer, CJoyDbSource& source, const CString& strIP, const CString& strUsername, const CString& strPassword, const CString& strDBName);
bool LoadDbSource(CJoyServer* pServer, CJoyDbSource& source, CJoyDbCommand& recordSet);
bool LoadDbSourceById(CJoyServer* pServer, CJoyDbSource& source, CJoyDbSession& servSess, UINT nId);
bool LoadDbSourceByType(CJoyServer* pServer, CJoyDbSource& source, CJoyDbSession& servSess, UINT nType);

class CJoyInvokeCommandIgnoreParam {};

extern CJoyInvokeCommandIgnoreParam InvokeIgnoreParam;

class CJoyDbBinary
{
public:
    const void* m_data;
    int     m_size;
public:
    CJoyDbBinary(const void* data, int size)
        : m_data(data), m_size(size)
    {
    }
    template<typename T>
    CJoyDbBinary(const T* data, int count)
        : m_data(data), m_size(count*sizeof(T))
    {
    }
};

class CJoyCommandInvoker
{
protected:
    PCSTR   m_file;
    int     m_line;
public:
    CJoyCommandInvoker(PCSTR pszFile, int nLine)
        : m_file(pszFile), m_line(nLine)
    {
    }

    bool InvokeCommandCreate(CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName, int nParamCount);
    bool InvokeCommandOpen(CJoyServer* pServer, CJoyDbCommand& dbCmd);
    void InvokeCommandSetParamFailed(CJoyServer* pServer, CJoyDbCommand& dbCmd, int n);

    template<typename T>
    bool InvokeCommandSetParam(CJoyServer* pServer, CJoyDbCommand& dbCmd, int n, T& p)
    {
        if(!dbCmd.SetParam(n, p))
        {
            InvokeCommandSetParamFailed(pServer, dbCmd, n);
            return false;
        }
        return true;
    }
    template<>
    bool InvokeCommandSetParam(CJoyServer* pServer, CJoyDbCommand& dbCmd, int n, const CJoyDbBinary& b)
    {
        if(!dbCmd.SetParam(n, b.m_data, b.m_size))
        {
            InvokeCommandSetParamFailed(pServer, dbCmd, n);
            return false;
        }
        return true;
    }
    template<>
    bool InvokeCommandSetParam(CJoyServer* pServer, CJoyDbCommand& dbCmd, int n, CJoyDbBinary& b)
    {
        if(!dbCmd.SetParam(n, b.m_data, b.m_size))
        {
            InvokeCommandSetParamFailed(pServer, dbCmd, n);
            return false;
        }
        return true;
    }

    template<typename T1>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 1))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 2))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 3))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 4))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 5))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 6))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 7))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 8))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 9))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9, T10& p10)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 10))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        InvokeCommandSetParam(pServer, dbCmd, 10, p10);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9, T10& p10, T11& p11)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 11))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        InvokeCommandSetParam(pServer, dbCmd, 10, p10);
        InvokeCommandSetParam(pServer, dbCmd, 11, p11);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9, T10& p10, T11& p11, T12& p12)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 12))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        InvokeCommandSetParam(pServer, dbCmd, 10, p10);
        InvokeCommandSetParam(pServer, dbCmd, 11, p11);
        InvokeCommandSetParam(pServer, dbCmd, 12, p12);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9, T10& p10, T11& p11, T12& p12, T13& p13)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 13))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        InvokeCommandSetParam(pServer, dbCmd, 10, p10);
        InvokeCommandSetParam(pServer, dbCmd, 11, p11);
        InvokeCommandSetParam(pServer, dbCmd, 12, p12);
        InvokeCommandSetParam(pServer, dbCmd, 13, p13);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9, T10& p10, T11& p11, T12& p12, T13& p13, T14& p14)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 14))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        InvokeCommandSetParam(pServer, dbCmd, 10, p10);
        InvokeCommandSetParam(pServer, dbCmd, 11, p11);
        InvokeCommandSetParam(pServer, dbCmd, 12, p12);
        InvokeCommandSetParam(pServer, dbCmd, 13, p13);
        InvokeCommandSetParam(pServer, dbCmd, 14, p14);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

    template<typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10, typename T11, typename T12, typename T13, typename T14, typename T15>
    bool operator () (CJoyServer* pServer, CJoyDbSession& sess, CJoyDbCommand& dbCmd, PCWSTR procName,
        T1& p1, T2& p2, T3& p3, T4& p4, T5& p5, T6& p6, T7& p7, T8& p8, T9& p9, T10& p10, T11& p11, T12& p12, T13& p13, T14& p14, T15& p15)
    {
        if(!InvokeCommandCreate(pServer, sess, dbCmd, procName, 15))
        {
            return false;
        }

        InvokeCommandSetParam(pServer, dbCmd, 1, p1);
        InvokeCommandSetParam(pServer, dbCmd, 2, p2);
        InvokeCommandSetParam(pServer, dbCmd, 3, p3);
        InvokeCommandSetParam(pServer, dbCmd, 4, p4);
        InvokeCommandSetParam(pServer, dbCmd, 5, p5);
        InvokeCommandSetParam(pServer, dbCmd, 6, p6);
        InvokeCommandSetParam(pServer, dbCmd, 7, p7);
        InvokeCommandSetParam(pServer, dbCmd, 8, p8);
        InvokeCommandSetParam(pServer, dbCmd, 9, p9);
        InvokeCommandSetParam(pServer, dbCmd, 10, p10);
        InvokeCommandSetParam(pServer, dbCmd, 11, p11);
        InvokeCommandSetParam(pServer, dbCmd, 12, p12);
        InvokeCommandSetParam(pServer, dbCmd, 13, p13);
        InvokeCommandSetParam(pServer, dbCmd, 14, p14);
        InvokeCommandSetParam(pServer, dbCmd, 15, p15);
        
        return InvokeCommandOpen(pServer, dbCmd);
    }

};

#define JoyInvokeCommand  CJoyCommandInvoker(__FILE__, __LINE__)

} // namespace JoyDbUtility

using namespace JoyDbUtility;

} // namespace JoyServer

#endif  // __DB_UTILITY_H_COMMON_SVR_BASE__